What's a more efficient way to do collisions? - arrays

Here's my dilemma
I have 4 walls around the stage of my game, when a player hits these walls I do not want to make an if statement for each and every one of the walls checking if the player is hitting it, so I have created an array to hold the walls, then check if the player is hitting that. Now, because I am doing this I will not know what the player is actually hitting if he hits something, and I cannot do a check in my array if he's hitting like [0], [1], [2] etc because then I'm back to doing the checks if he's hitting specific walls. The reason I don't want to do that is for the future, when I add more barriers, buildings, and so on.
So my question is, how can I do collision checks, without hard coding checks on specific objects, and giving some sort of value that can be used for the player to respond to, for example if your hitting the top wall and you can figure that out somehow without doing the above, then make it so you can't walk through or something,
if (main.playerPosKeeper_mc.hitTestObject(this[main.StageCollisions]))
{
trace("hit");
}
StageCollisions is an array which contains all of my barriers in it.
When the player hits anything in StageCollisions, I cannot just simply subtract from his y value, or x value, because I do not know which object he hit, but I also do not want to hard code it so that I check if I'm hitting lets say the top barrier, because then why do an array in the first place if I'm just going back to making static if else statements.
^^ Refrencing this topic
AS3 - How to Cycle States of Character Animations (moving & stopped)
This has been stumping me for a little while, so help would be greatly appreciated. It is a hard question to form so I can clarify points if necessary.

So my question is, how can I do collision checks, without hard coding
checks on specific objects, and giving some sort of value that can be
used for the player to respond to, for example if your hitting the top
wall and you can figure that out somehow without doing the above, then
make it so you can't walk through or something
Right, so you want a way to perform a generic collision response. This can be a big topic. The simplest approach is usually to check for a collision after a move, then reverse the move if there's a collision.
Something like this:
function movePlayer(movementX:Number, movementY:Number):void {
var originalX:Number = player.x;
var originalY:Number = player.y;
player.x += movementX;
if (checkCollision()) {
player.x = originalX;
}
player.y += movementY;
if (checkCollision()) {
player.y = originalY;
}
}
function checkCollision():Boolean {
for each (var wall:MovieClip in walls) {
if (player.hitTestObject(wall)) {
return true;
}
}
return false;
}
This way you could have checkCollision() check 4 walls or 50 walls, it doesn't matter. It won't let the player move into them.
This is just a starting point and there are many ways it can break down or be refined.

Some trivial pseudo code for you to study:
private function collisionCheck(h:Sprite):Sprite{ // pass the hero Sprite into this function and it will return the wall that it hit
for each (b:Sprite in blockArray){ // if your array of hit-able objects is called "blockArray"
if (h.hitTtestObject(b)){ // check the hero Sprite against all objects in the array
return b;
}
}
return null;
}
Then, elsewhere in your code (maybe in your gameTick function or gameLoop function or wherever you have your game logic repeating on each frame:
private function gameTick():void{
var objectHit:Sprite = collisionCheck(_myHero); // this will run the collision check function, and return the sprite that the hero collides with;
if (objectHit != null){
objectHit.alpha = 0.5;
// this will give you a visible representation that your code is indeed working, or not.
}
}
For those moments when your hero isn't colliding with anything, this function will return null. That's why I first check if objectHit is not null before trying to perform an operation on its alpha value. Of course, you will do something other than change its alpha value in your project, but this is something I often do (with the alpha) to quickly get a visual confirmation that things are detecting what they are supposed to.

Related

Is there a way to go back after you go forward with an 'IF' statement?

So I'm making this text based game for my 'C' Programming class.
I want to continue it even after I'm done with the class so it's not just a homework assignment I want to actually keep it for later use.
My question is in this part of the code is there a way to send the user back to the previous question asked when using an 'IF' statement so they can make multiple choices before ultimately going the direction of the story?
if (door2 == 1)
{
// what happens when you touch the orb.
printf("The orb transports you to an unknown location.\n");
printf("You look around to get the lay of your area,\n");
printf("off in the distance you see a church like building.");
door2 = door2 - 1;
printf("\n");
printf("Do you go to the building? ");
scanf_s("%d", &door1);
printf("\n");
if (door1 == 1)
{
// Going up to the church.
printf("You walk up to the building, it gives you a strange feeling\n");
printf("in the pit of your stomach. You look around and see two windows\n");
printf("low enough for you to see into along with the main door.\n");
printf("Do you go to the left window? right window? or try to open the front door?\n");
scanf_s("%d", &movement);
printf("\n");
if (movement = 1)
{
// left window.
printf("You creep up to the window and peak inside...\n");
printf("You see a large figure pacing back and forth in the room\n");
printf("what ever it is spots you and darts further into the church.");
movement = movement - 1;
// i subtract the L,S,R numbers to insure there is not an infinite loop.
}
else if (movement = 2)
{
// front door.
printf("You walk up to the front door, and try to open it.\n");
printf("The door does not budge, it must be locked.");
movement = movement - 2;
}
else if (movement = 3)
{
// right window.
printf("You creep up to the window and find an empty room.\n");
movement = movement - 3;
printf("The window is cracked open somewhat... Do you try to enter the\n");
printf("church through the window? ");
scanf_s("%d", &door2);
printf("\n");
}
Actually yes, if you would just put a loop around that, but i'd advise splitting your ifs in functions. Your code will look much better.
void main() {
enterTheCurch();
}
void enterTheCurch() {
printf("You've entered the Curch. There are 2 Doors. Do you want to go left or right?");
String direction;
scanf_s("%s", &direction);
if(direction == "left") {
goLeftCurchDoor();
}
else {
goRightCurchDoor();
}
}
goLeftCurchDoor() {
...
}
goRightCurchDoor() {
...
}
Try using this structure. Like this you also can give parameters to the function like bool alreadyVisited and change the prints depending on these parameters.
This is probably not the correct approach at all. A game generally is split into several components: a main loop (that runs infinitely), an update loop (that simulates the game world) and a process input function (which takes input from the user.)
The way your code is structured also leaves much to be desired. For one thing, your prompts to the user are inconsistent. Sometimes you seem to be asking a yes or no question, other times it seems you want a movement command with no indication to the user which is expected. This is a UX nightmare. Instead, you can treat each movement as an action. For example, going forward to a locked door means the user wants to try to open the door. Going forward with an open window means the user wants to travel through the window. With that in mind, it becomes clear that you only actually need to keep track of one variable.
Making a game is not an easy task and you cannot brute force your way into making one - it requires thoughtful planning ahead of time. Try drawing a dialogue tree on a piece of paper. You'll quickly see it spiral out of control as you run out of room on the paper - designing a game is a complex task. It's important to have a blueprint before you begin coding.
First, let's tackle what your game loop can look like:
#include <stdio.h>
#include <stdbool.h> // for true and false
typedef enum { NONE = 0, LEFT, RIGHT, UP, DOWN } movement_t;
int main()
{
movement_t movement = NONE;
movement_t last_movement = NONE;
while (true)
{
int movement_input = 0;
scanf("%d", &movement_input);
movement = (movement_t) movement_input;
// ...
last_movement = movement;
}
}
Now you want to know what kind of data structure should represent your game. Unfortunately this is a complex topic and I'm not a game developer, so I'll try to present a naive approach. The simplest way that takes less work is to have a static message for each room as you enter it. If something changes, then you could reflect that change once a variable has been updated.
void church()
{
printf("Generic church description.");
if (some_player_did_something)
{
printf("You now spot a shiny object on the floor.");
}
}
Keeping track of the player's last movement (which I have demonstrated above) is useful for determining where they came from.
if (last_movement == LEFT)
{
printf("You come in from the left and noticed something you haven't before...");
}
I would take the suggestions from the others and split your code into functions (as I'm sure your instructor has drilled into you by now.) A monolithic approach is not the way to go.
There is one: goto.
label:
if (someCondition) {
goto label;
}
This code will loop until someCondition becomes false.
goto is a inconditional jump, and allow you to jump excecution forward or backward to a label, provided you stay in the same scope.
Lots of people hates goto, and you should make sure not to use it if you have other better alternatives.
Story telling sounds like a nice use case for goto.
Loops or recursion are other options to produce this result, such as while do ... while for.
each location in the game needs an entry in a table,
along with certain environment details such as:
which direction is the player facing
visible items at each location
current game state,
current inventory,
'next' table entry to use, etc.
This table grows huge very quickly and can have many parameters per line in the table. It is the actual game. All the rest is just user manipulation of the table, current conditions, etc.
Every possible user input has a unique function to handle that input (there are not that many possible inputs).
Each of these functions gets a parameter that is a pointer to an entry in the location table, that lets that function process the user input.
The main loop of the program handles getting input from the user and dispatching the appropriate inputFunction handler.
There will be sub functions to handle inventory changes, display inventory, enable/disable certain types of actions, etc

Movie Clip through Display Object Not working correctly

Hey everyone so I have a movie Clip called popEffect that i want to show on the current bubbles that are being clicked by the mouse. Now Whenever I click on a Bubble everything works correctly they get removed from the stage, but the problem I am having is that the popEffect is not positioned to the current bubbles that are being clicked. Instead they are positioned at a different bubble that shows on the screen in the display object array.
Here is how I have it all set up:
private function addBubbles(e:TimerEvent):void
{
bubbles = new mcBubbles();
stage.addChild(bubbles);
aBubbleArray.push(bubbles);
bubbles.addEventListener(MouseEvent.CLICK, bubblesBeingClicked);
}
Then the BubblesBeingClicked function:
private function bubblesBeingClicked(e:MouseEvent):void
{
var BubblePop:DisplayObject = e.target as DisplayObject; // HERE is your clicked square
var i:int = aBubbleArray.indexOf(BubblePop); // and HERE is your index in the array
if (i < 0)
{
// the MC is out of the array
//trace("Pop Clicked");
onBubbleIsClicked(BubblePop);
aBubbleArray.splice(i, 1);
BubblePop.parent.removeChild(BubblePop);
//Remove Listeners!!!
BubblePop.removeEventListener(MouseEvent.MOUSE_DOWN, onBubbleIsClicked);
// Null
BubblePop = null;
}
}
Finally my onBubbleIsClicked function where i have the popEffect located:
private function onBubbleIsClicked(bubblePop:DisplayObject):void
{
nScore++;
updateHighScore();
//Pop Effect
popEffect = new mcBubblePop();
stage.addChild(popEffect);
popEffect.x = bubbles.x;
popEffect.y = bubbles.y;
}
Can anyone see why the popEffect wont position on the current bubble that is being popped? Its acting really weird.
The reason is this:
popEffect.x = bubbles.x;
popEffect.y = bubbles.y;
As far as I can understand, bubbles is a member variable in the class (you are using it in the addBubbles function. Inside onBubbleIsClicked, you provide bubblePop, but do not use it. You are using bubbles instead, which is actually the last instance you've created inside the tick function!
So every time you create popEffect, you actually assign the x and y to the latest created bubblePop.
Some advises:
Do not use member variables that often. They are used WHEN you need to use a variable between functions. In your case, bubbles is a variable that is used only inside the creational function. You even put them into an array! And because you override it with a new one every time you create an instance, your member variables just saves the last one. Is this really needed? Same with popEffect, does anyone else uses it, as it's again just the last one? Such things create mistakes, as you see..
I truly don't understand what this means: if (i < 0). You search if the object you've clicked is not in the array? Well if it is not (how come?!), then what's the meaning of aBubbleArray.splice(i, 1);? Since i < 0, you actually splice with negative value, so you splice some other element! Plan what you want to do, thing logically and then do the actual code. If the object is not in the array, then why do you remove anything from the array?
Start formatting your code better. Read about camel case and variables scope.
Try to manage your logic better. For example this is pretty awkward: BubblePop.parent.removeChild(BubblePop);, as long as you've added it by using stage.addChild(bubbles);. So isn't it more simple to use stage.removeChild(child);? There are some rules in programming (especially in Flash), like 'what added it should remove it'. This will keep you safe in future.
Good luck!

How to effectively garbage collect in AS3

I have a flash game that I'm building where I have an array keeping track of a bunch of power ups on the screen. When the player goes an grabs one it needs to disappear from the screen (which is easy) but it also needs to be removed from the array so that collision detection loops don't become really cumbersome. I tried using splice, but I keep get null reference errors, here's the relevant code.
public function collect():void {
try {
Main.powerUps.splice(index, 1);
stage.removeChild(this);
}catch (e:Error) {
trace("Error in splice");
}
}
}
Then when I create my PowerUp object I pass it a parameter that gets assigned to index which is the length of the array of Power Ups at the time. Can anyone see what's wrong with this code or (preferably) provide a more elegant solution? Thanks in advance for any help.
Elegant solution: use indexOf() and splice() together!
var index:int = Main.powerUps.indexOf( powerup );
Main.powerUps.splice(index, 1);
Where powerup is a reference to the object stored within the array Main.powerUps.
I also created a little class a while back that may be useful to you:
https://github.com/MartyWallace/Lotus/blob/master/Lotus/lotus/utils/Set.as
It has a .remove() method so you can just do:
powerUps.remove(powerup);

Moving x,y position of all array objects every frame in actionscript 3?

I have my code setup so that I have a movieclip in my library with a class called "block" being duplicated multiple times and added into an array like this:
function makeblock(e:Event){
newblock=new block;
newblock.x=10;
newblock.y=10;
addChild(newblock);
myarray[counter] = newblock; //adds a newblock object into array
counter += 1;
}
Then I have a loop with a currently primitive way of handling my problem:
stage.addEventListener(Event.ENTER_FRAME, gameloop);
function gameloop(evt:Event):void {
if (moveright==true){
myarray[0].x += 5;
myarray[1].x += 5;
myarray[2].x += 5
-(and so on)-
My question is how can I change x,y values every frame for new objects duplicated into the array, along with the previous ones that were added. Of course with a more elegant way than writing it out myself... array[0].x += 5, array[1], array[2], array[3] etc.
Ideally I would like this to go up to 500 or more array objects for one array so obviously I don't want to be writing it out individually haha, I also need it to be consistent with performance so using a for loop or something to loop through the whole array and move each x += 5 wouldn't work would it? Anyway, if anyone has any ideas that'd be great!
If you have to move 100 objects, you have to move them. No alternatives.
But what you can really do to save performance, is optimize the solution itself. A few cents from me:
Of course the loop has to be applied in your case, managing 100+ assignments line by line is definitely not the right way to go. Although you gain nothing performance wise with just using a loop.
Try grouping the objects. As I see above, you seem to be moving all those objects with similar increment. Group them all into larger movieclips (or Sprites) & move that instead.
Learn Blitting & caching methods to save a lot on performance, Or you would sooner or later hit on the road where your logic cannot be twisted anymore & performance will be a pain.
Also, in extent of the previous step, do consider using Sprite Sheets if you have multiple states of the same object.
Finally, I would also like to caution you to not waste time on micro optimizations & thinking about them.
You can use some container sprite and add the blocks to that on creation:
// Some init place
var blockContainer:Sprite = new Sprite();
addChild(blockContainer);
Make the blocks:
function makeblock(e:Event){
newblock=new block;
newblock.x=10;
newblock.y=10;
// Add the block to the container
blockContainer.addChild(newblock);
myarray[counter] = newblock; //adds a newblock object into array
counter += 1;
}
And the gameloop:
stage.addEventListener(Event.ENTER_FRAME, gameloop);
function gameloop(evt:Event):void {
if (moveright==true){
blockContainer.x += 5;
}
// etc...
}
This way you'll only have to move one object. Of course this method will only work so long as all the blocks need to move in the same direction. By the way, a for loop will work just as well - 500 iterations is nothing. The only performance issue will likely be just rendering and that will happen regardless of what method you choose, as you have to somehow move the blocks (in other words, performance here is not really the issue as you have to render the movement change, the only question is how you choose to implement the movement for your own coding convenience).

How can I create arrays within a loop (within another loop) and pass them back out in Javascript?

I'm using Google Docs Spreadsheet API to keep track of a competition between some of my friends. I have some big ideas, but I'm stumped right now. I'm trying to create 20 different arrays inside of loops (see below) and then evaluate each one outside of the loop, and I really don't want to write 20 "if...then" statements.
NOTE: the following SUMMARY may or may not help you answer my question. You might want to skip down to the code, then read this if you need it :)
Summary of the program: Each player assigns point values in favor of one possible outcome of a set of binary-outcome events. As the events happen, players either gain the points assigned if their outcome occurs, or gain no points if the opposite outcome occurs. My goal is to 1) figure out exactly when a player is eliminated, and 2) highlight all remaining events that must be won for them to have a chance at tying for first.
Instead of trying to somehow evaluate all possibilities (5 players picking, 2^16 outcomes... I have zero computer science knowledge, but this seems like an incredibly huge task even for the modern computer) I've come up with an alternate idea. The script loops through each player, against each other opponent. It calculates the maximum number of points a player can score based on their value assignments and the already determined game. For one player and one opponent, it checks the best possible outcome by the player against that opponent, and if there is any opponent he cannot beat, even in the best case, then he is eliminated.
This part is easy-- after the loop runs inside the loop, I just adjust a global variable that I created earlier, and when the outer loop is done, just grab those variables and write them to the sheet.
Unfortunately, this misses the case of where he could have a best case against each individual opponent, but not against multiple opponents at once.
So the next step is what I'm trying to do now. I'm not even sure I can give a good explanation without just showing you the entire spreadsheet w/script, but I'll try. So what I want to do now is calculate the "value" of each event for each player against a given other player. If both player and opponent assigned points in favor of the same event outcome for one event, the event's value is the difference between the picks (positive if player picked higher, negative if lower), and it's the SUM if they picked opposite event outcomes. Now, I do the same thing as before-- take a best-case scenario for a player against a given opponent-- but now I check by how much the player can beat the opponent in a best-case scenario. Then I evaluate the (absolute value of the) event value against this difference, and if it's greater, then the event is a must win (or must lose if the event value is negative). And, if an event is both a "must-win" and a "must lose" event, then the player is eliminated.
The problem is that this second step requires me to create a new array of values for each player-opponent combination, and then do things with the values after they're created.
I realize one approach would be to create 20 different arrays, and throughout the entire loops, keep checking "if (player == "1" && opponent == 2){}" and populate the arrays accordingly, but this seems kind of ridiculous. And more importantly, this entire project is my attempt at learning javascript, so what's the point in using a time-intensive workaround that doesn't teach me anything new?
I'm trying to understand square bracket notation, since it seems to be the answer to my question, but a lot of people are also suggesting that it's impossible to create variable names by concatenating with the value of another variable... so anyway, here's what I'm trying. I'd really appreciate either a fix to my approach, or a better approach.
for (var player=1; player<6; player++){
if(player==1){look up certain columns in the spreadsheet and save them to variables}
//ditto for other players
for(var opponent=1; opponent<6; opponent++){
if(player!=opponent){
if(opponent==1){save more values to variables}
//ditto for other players
for(var row=9; row<24; row++) {
//Now the script goes down each row of an array containing the original
//spreadsheet info, and, based on information determined by the variables
//created above, get values corresponding to the player and opponent.
//So what I'd like to do here is create "array[1,2]==" and then "array[1,3]=="
//and so forth, creating them globally (I think I understand that term by now)
//so I can refer to them outside of the loops later to do some evaluatin'.
}
}}
//get array[1,2]...array[5,4] and do some operations with them.
Thanks for getting through this little novel... really looking forward to your advice and ideas!
How can I create arrays within a loop (within another loop)?
Code update 2
As you said: "i am trying to understand square bracket notation" You may take a look at my new demo and the code:
function getTeam(){
var array = [[1,2,3],[4,5,6],[7,8,9]]; // arrays within arrays
// array myTeam
var myTeam = [[],[],[],[]];
var playerNames = ["John", "Bert", "Dave", "Milton"];
var ages =[];
var weight = 104;
// loop over the team arrayadd each player (name, age and weight) to the team
for (i=0; i < myTeam.length; i++){
// fill the age array in a loop
for (j=0;j<myTeam.length;j++) {
ages[j] = 23 + j;
}
myTeam[i].push([playerNames[i], ages[i], weight]);
}
return myTeam;
}
And pass them back out in Javascript
Could you elaborate on this part?
Update
var valuesOfPlayers=[];
for (var player=1; player<6; player++){
// look up certain columns in the spreadsheet and save them to variables
// you could call a funcntion and return the values you
// collected in an array within an array as in the demo above
valuesOfPlayers[player] = lookupColumnValues(player);
for(var opponent=1; opponent<6; opponent++){
if(player!=opponent){
// save more values to variables
valuesOfPlayers[player] = addValuesToVar(player);
}
for(var row=9; row<24; row++) {
// if you collect the values in your first and second if clause
// what other information do you want to collect
// Please elaborate this part?
}
}}
One workaround:
I could create an array before the execution of the loops.
At the start of each loop, I could push a string literal to the array containing the value of player and opponent.
After the loops are done, I could split the array into multiple arrays, or just evaluate them in one big array using regular expressions.
I'd still rather create new arrays each time-- seems like it is a more universal way of doing this, and learning how would be more educational for me than using this workaround.

Resources