Why does my code oscillate before it sets the screen? And why does it eventually set? - nand2tetris

I am trying to code Fill.asm from Unit 4. My code has a major bug though: when you press a key in order to set the display, it seems to oscillate between a black and white screen a few times, then set to a black screen. It resets just fine. I cannot find where this is coming from, and why the fact that the oscillation breaks eventually is even more confusing.
My code is relatively well commented.
Here is my code:
// This file is part of www.nand2tetris.org
// and the book "The Elements of Computing Systems"
// by Nisan and Schocken, MIT Press.
// File name: projects/04/Fill.asm
// Runs an infinite loop that listens to the keyboard input.
// When a key is pressed (any key), the program blackens the screen,
// i.e. writes "black" in every pixel;
// the screen should remain fully black as long as the key is pressed.
// When no key is pressed, the program clears the screen, i.e. writes
// "white" in every pixel;
// the screen should remain fully clear as long as no key is pressed.
// Put your code here.
// gets KBD contents, loads it into D, and checks if its greater than 0. If so, we jump to Fill, else we re-listen
(Listen)
#KBD
D=M
#Fill
D; JGT
#Listen
0; JEQ
(Fill)
//inits counter to 8192
#8192
D=A
#counter
M=D
(FLoop)
//sets address to SCREEN + counter
#counter
D=M
#SCREEN
A = A+D
//sets data at adress to all 1s
M=-1
//decrements counter & jumps back to FLoop
#counter
M=M-1
D=M
#FLoop
D;JGT
//once we finish loop, we jump to wait to clean
#WaitToClean
0;JEQ
//once we get through loop, the screen is black
//listen until the key is unpressed, then clear screen
(WaitToClean)
#KBD
D=M
#WaitToClean
D; JGT
#ClearScreen
0;JEQ
(ClearScreen)
//resets counter to 8192
#8192
D=A
#counter
M=D
(CLoop)
//sets address to SCREEN + counter
#counter
D=M
#SCREEN
A = A+D
//sets data at adress to all 0s (white)
M=0
//decrements counter & jumps back to CLoop
#counter
M=M-1
D=M
#CLoop
D;JGT
//once we are done, we jump back to the listen loop
#Listen
0;JEQ

Related

Actionscript 3.0 Splice/RemoveChild issue

I have rocks and enemy ninjas moving off the screen. The ninjas are supposed to disappear after being hit by a shuriken once, however they are taking two hits to disappear, although the shurikens disappear every time fine. The code is nearly identical for the shurikens and enemy ninjas, however the ninjas don't seem to work properly. I also get the occasional ninja getting stuck somewhere on the screen and shurikens pass through it.
//If a rock moves off the screen, it is spliced.
if (rock[j].x <= -301){
removeChild(rock[j]);
rock.splice(j, 1);
rockNum--;
}
}
for (var q=shurikens.length - 1; q >= 0; q--){
for (var w=enemy.length - 1; w >= 0; w--){
//If the shurikens hit the ninjas.
if ((shurikens[q]).hitTestObject(enemy[w])){
removeChild(enemy[w]);
enemy.splice(w, 1);
ninjaNum--;
removeChild(shurikens[q]);
shurikens.splice(q, 1);
break;
}
}
}
}
How to fix your code, and give you some performance tips:
This code is very "bug friendly": you are modifying the "length" property of array within a for/in loop that relied on the same property, this is really not a wise thing to do.
The way I would do it:
// Create an array where to store colliding ninjas and shurikens
var depleted:Array = [];
// Create local references to make code more readable and fast (querying arrays all the time is slow).
var ninja:DisplayObject;
var shuriken:DisplayObject;
// Loop in shurikens (no need to check if shurikens have been depleted, since you query only once each of them
for (var q:int=shurikens.length - 1; q >= 0; q--){
shuriken = shurikens[q]; // Assign a shuriken to our variable so you avoid to call further shurikens[q];
for (var w:int=enemy.length - 1; w >= 0; w--){ // Loop in ninjas
ninja = enemy[w]; // Assign ninja
//If the shurikens hit the ninjas. (only if ninjas have not yet been removed)
// This is the core of our improvement, before calling hitTest that is slow, you first check that ninjas have not already been killed
if (depleted.indexOf(ninja) == -1 &&
shuriken.hitTestObject(ninja)){
// It's a hit with a live ninja. I just add both objects to depleted list.
depleted.push(ninja);
depleted.push(shuriken);
break; // Breaking the loop, makes sure shuriken cannot hit 2 ninjas
}
}
}
// Then, you loop in the list of killed ninjas and depleted shurikens, and remove them from arrays and display list
for each (var depletedObj:DisplayObject in depleted) {
// First remove object from the relevant array
if (shurikens.indexOf(depletedObj) != -1) shurikens.splice(shurikens.indexOf(depletedObj), 1); // If it was in the shurikens array remove from there
else if (enemy.indexOf(depletedObj) != -1) enemy.splice(enemy.indexOf(depletedObj), 1); // If it was in the ninjas array remove from there
// The do all necessary stuff to remove object from DisplayList (end eventually add it to an object pooling list)
removeChild(depletedObj);
}
ninjaNum = enemy.length; // Update number of ninjas
Another hint, in case you run this for loops on each frame, if you place ninjas and shurikens in 2 different DisplayObjectContainer, you can first hitTest the 2 large containers, and once they collide, you can run the loops to check fine collisions. Also, in numeric for/in loops, declare variables always as :int. Typing variable makes it faster to access than an untyped variable. You can of course improve this code to make it faster, i.e.: adding a "alive = true" property to shurikens and ninjas, so you do not need to query a third array, etc.

Nape Resulting Impulses

I'm trying to make the player body, when certain condition is met, to go up few "meters" then stop slowly in the "air" and come down.
The gravity is 600
public var gravity:Number = 600;
public var space:Space = new Space(new Vec2(0, gravity));
I thought that for it to go up, the impulse.y should be at least -601, to contradict the force that pushes it down. Although, setting -600 (or even smaller) will shoot it upwards never to be seen again. (even -100).
Yes the impulse is in the update function which means it will constantly add the impulse making it faster per tick. However, when setting -20 it doesn't go up in the y, (it should eventually as impulse is being given to the body per tick).
switch (combo)
{
case "W":
break;
case "WW":
impulse.x = 0.0;
impulse.y = -powerJump;
mainChar.applyImpulse(impulse);
powerJump -= 5;
break;
}
This is not finished and it is not what is described above but it's the gist of it. When condition is met the player should go upwards and the impulse should lose it's force. The problem is I don't know how much is sufficient to counter the gravity impulse. I can do it by trial'n error but I'd rather know how it works, how much impulse is equivalent to gravity=600?

How to create a loop between the mask and the background image in AS3 when mouseover

I am new in AS3, for one of my assignment, I need to modified the existing code(copy paste and modify) to create certain effect. The effect that I need to create is when I MouseOver on the stage, the mask will form a loop with background image and back to normal(mask layer not visible) when I MouseOut of the stage. Here is the code that need to modifly.
var mymask:Sprite=new Sprite();
var isOver:Boolean=false;
var spotSize:Number=0;
pic2.addChild(mymask);
pic2.mask=mymask;
pic2.mouseEnabled=false;
mymask.x=0;
mymask.y=0;
function drawSpot(r:Number):void{
mymask.graphics.clear();
mymask.graphics.lineStyle(1,0x000000);
mymask.graphics.beginFill (0x00000F);
mymask.graphics.drawRect(0,0,r,900);
mymask.graphics.endFill();
spotSize=r;
}
pic1.addEventListener(MouseEvent.ROLL_OVER, mouseOver);
function mouseOver(e:MouseEvent):void{
isOver=true;
}
pic1.addEventListener(MouseEvent.ROLL_OUT, mouseOut)
function mouseOut(e:MouseEvent):void{
isOver=false;
}
stage.addEventListener(Event.ENTER_FRAME, enter);
function enter(e:Event):void{
var cursorSize:Number=spotSize;
if(isOver==true && cursorSize<1)
drawSpot(cursorSize+999);
if(isOver==false && cursorSize>10)
drawSpot(cursorSize-999);
}
Sounds like you're trying to animate a circular mask by modifying the code above?
If so, this is the code changes needed.
In your drawSpot method, change the line:
mymask.graphics.drawRect(0,0,r,900);
to:
mymask.graphics.drawCircle(pic2.width * .5, pic2.height * .5, r);
Then in your enter method,
function enter(e:Event):void{
var cursorSize:Number=spotSize;
if(isOver==true && cursorSize<999)
drawSpot(cursorSize+1);
if(isOver==false && cursorSize>0)
drawSpot(cursorSize-1);
}
What you're doing is saying IF the mouse is over and the cursorSize is less than the full value (you had 999 before so I kept that) then increment the size by 1. It will keep doing this every frame until the size is 999 or higher (or the mouse is no longer over).
If the mouse isn't over and the mask isn't 0 in size, it will decrease the size by 1 every frame until it's 0 or less.
If you want it to go faster, simply change the +1 and -1 to a higher number

Actionscript 3 smooth Sprite movement

I move a Sprite across the screen using the keyboard, at a rate of 10 pixels/ENTER_FRAME event fire. The issue is that, when it moves, you can see it being "redrawn" every 10 pixels, which makes it hard to look at. I haven't seen this in other Flash games.
If you look closely, you can also see this here (although at a much lower scale): http://kirill-poletaev.blogspot.com/2010/07/smooth-character-movement-using-as3.html
I want to get rid of that effect, any ideas?
If the player is at a distance of ... from the screen edge, it stops moving (by moving in the opposite direction), and the BG starts scrolling (the same visual effect can be seen).
Music in playing in the background, a minimap is updated with the player's position.
private function updater(e:Event):void
{
if(up && GlobalVars.vars.upPossible)
{
cont.y-=unit;
setu(); // Player graphics state
}
else if(down && GlobalVars.vars.downPossible)
{
cont.y+=unit;
setd(); // Player graphics state
}
else if(left && GlobalVars.vars.leftPossible)
{
cont.x-=unit;
setl(); // Player graphics state
}
else if(right && GlobalVars.vars.rightPossible)
{
cont.x+=unit;
setr(); // Player graphics state
}
else
{
ups.visible=false; downs.visible=false; rights.visible=false;
lefts.visible=false; normals.visible=true; // Player graphics state
GlobalVars.vars.scXr=0; GlobalVars.vars.scYu=0; GlobalVars.vars.scXl=0;
GlobalVars.vars.scYd=0; cont.x=int(cont.x); cont.y=int(cont.y); //Someone from the Kongregate.com forums suggested this, no visible effect
}
if((cont.x=GlobalVars.vars.maxX))
{
if(cont.x=GlobalVars.vars.maxX && right && GlobalVars.vars.canScrollR) GlobalVars.vars.scXr=1, cont.x-=unit, setr();
}
else GlobalVars.vars.scXl=0, GlobalVars.vars.scXr=0; //BG Scrolling
if((cont.y=stage.stageHeight*7.3/10))
{
if(cont.y=stage.stageHeight*7.3/10 && down && GlobalVars.vars.canScrollD) GlobalVars.vars.scYd=1, cont.y-=unit, setd();
}
else GlobalVars.vars.scYu=0, GlobalVars.vars.scYd=0; //BG Scrolling
if(cont.y>=stage.stageHeight*7.3/10 && cont.x>=GlobalVars.vars.maxX) GlobalVars.vars.minimapTr=1;
else GlobalVars.vars.minimapTr=0;
if(cont.y-unitGlobalVars.vars.sH-cont.height-3.1) GlobalVars.vars.downPossible=false;
else GlobalVars.vars.downPossible=true;
if(cont.x-unitGlobalVars.vars.sW-cont.width-3.5) GlobalVars.vars.rightPossible=false;
else GlobalVars.vars.rightPossible=true;
GlobalVars.vars.plX=cont.x; //for minimap
GlobalVars.vars.plY=cont.y;
Also, key listener functions:
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyD, false, 0, true);
stage.addEventListener(KeyboardEvent.KEY_UP, keyU, false, 0, true);
private function keyD(e:KeyboardEvent):void
{
if(e.keyCode==37 || e.keyCode==65) left=true;
if(e.keyCode==38 || e.keyCode==87) up=true;
if(e.keyCode==39 || e.keyCode==68) right=true;
if(e.keyCode==40 || e.keyCode==83) down=true;
}
private function keyU(e:KeyboardEvent):void
{
if(e.keyCode==37 || e.keyCode==65) left=false;
if(e.keyCode==38 || e.keyCode==87) up=false;
if(e.keyCode==39 || e.keyCode==68) right=false;
if(e.keyCode==40 || e.keyCode==83) down=false;
}
I've encountered some improvement by increasing the FPS to 120, and decreasing the step to 4, but it's still there. I'm fairly sure it's not a performance issue, but, rather, a movement method fault.
A couple of suggestions:
Increase the frame rate
Use a tween library (e.g. GTween) with some easing effect.
Basically, if you want the object to jump 10px to the right, don't just move it right away, let it animate to its new position with some easing effect. Additionally, if the object is still moving and the key is pressed again, you probably want to accelerate the movement a bit (but only up to a point!).
I think you're asking how to make it more smooth. Well:
If you change the movement 2px per frame, then you'll have a much smoother experience. However, the movement will see very slow. To combat this, you just increase the frame rate of your swf. I believe the maximum is 120 frames, but that should be more than enough.
I love Tweenlite, it's great for pre-defined effects. It isn't for the core of your game though so I'd use Tweenlite for UI effects but barely for ingame movements responding to user controls.
I think around 24-30 fps for games is great, that's how I set all my games. I think abit you're picky, but perhaps what you're missing is a bit of edge: a smooth start and end for the movement. In most platformers I have a similar mechanic:
You want the start of the movement to start slow, reach the normal (max) speed you define and when the player lets go of a button, it slows down back to 0. This means you need to check the speed on enter frame regardless of the button triggers (they increment the speed but aren't the only condition to change speed and move the object)
enterframe loop:
//check for each direction:
if up, y_speed++
else if down, y_speed--
else if right, x_speed++
else if left, x_speed--
else // perform a decrease:
y_speed *= .8
x_speed *= .8
// make sure we aren't past the max speed
if x_speed>max_x_speed
x_speed = max_x_speed
etc. else other direction and y_speed
// now apply the movement
object.x += x_speed
object.y += y_speed
// remove the enterframe for better performance
if math.abs(x_speed)<.1 && math.abs(y_speed)<.1
// remove enterframe for movement here, add it again next time we know we have movement (button downs related to the movement, etc.)
I would implement this in your code but your code is too crowded. Anyway otherwise, most games with these simple controls are working just like your application does.

Replay a timeline two times in as3

stop ()
Is there a function what will play a timeline two times and after it stops ?
from frame 1 to 15 I want it to play two times and stop after. I don't want to duplicate timeline.
No code needed:
make your animation a graphic
click on the graphic and under properties set
option: Loop
First: 2
and it will loop 2 times :-)
var i = 0; // put this on a blank first frame
// put this on the last frame
i++;
if(i==2){
stop();
}else{
gotoAndPlay(1); // that might be 0 not sure a bit rusty on flash
}
I'm not promising this will work because I haven't messed with flash in a few months but you can give it a try.
var loop:int = 2;
var counter:int = 0;
Put this to first frame and leave it empty, start animation from second frame.
if(counter == loop){
stop();
}
And copy this block to where you want animation to stop.
counter++;
gotoAndPlay(2);
Copy this to last frame
Put this code into the last frame. // we did not assign any value to the variable loopCount and use condition for assigning value in our variable loopCount. and second time first condition will not run and loopCount value will not change. then we are increasing loopCount value by 1 in every loop of animation. then just write condition to stop the movie by checking loopCount value.
//Put this code into the last frame or where you want to stop your movie after playing 2 times.
if(!loopCount){var loopCount:Number = 0;}
loopCount++;
if(loopCount >= 2){stop();}